package com.cqq.common.core.util;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.cglib.beans.BeanCopier;

/**
 * <h3>Bean工具类</h3>
 *
 * <p>
 * 复制有相同字段名称及类型定义的Bean
 * </p>
 * 
 * @author xijq
 * @version 1.0.0
 * 
 */
public class BeanUtil {
	
	private static Map<String,BeanCopier> copierCache=new HashMap<String,BeanCopier>();
	
	/**
	 * <h3>将源对象的数据复制到目标对象</h3>
	 * 
	 * @param source 源对象
	 * @param target 目标对象
	 * @see BeanUtil#copy(Object, Class)
	 */
	@Deprecated
	public static void copy(Object source, Object target){
		if(source==null){
			target=null;
			return;
		}
		if(target==null){
			throw new IllegalArgumentException();
		}
		String key=source.getClass().getName()+","+target.getClass().getName();
		BeanCopier copier=copierCache.get(key);
		if(copier==null){
			copier = BeanCopier.create(source.getClass(), target.getClass(), false);
			copierCache.put(key, copier);
		}
		copier.copy(source, target, null);
	}

	/**
	 * <h3>将源对象的数据复制到目标对象</h3>
	 * 
	 * @param <T> 目标对象类型
	 * @param source 源对象
	 * @param targetType 目标对象类型
	 * 
	 * @return 目标对象类
	 */
	public static <T> T copy(Object source, Class<T> targetType){
		if(source==null){
			return null;
		}
		if(targetType==null){
			throw new IllegalArgumentException();
		}
		T target;
		try {
			target = targetType.getConstructor().newInstance();
		} catch (Exception e) {
			throw new IllegalArgumentException(e);
		}
		copy(source, target);
		return target;
	}
	
	/**
	 * <h3>将源对象列表的数据复制到目标对象列表</h3>
	 * 
	 * @param <S> 源对象类型
	 * @param <T> 目标对象类型
	 * @param sources 源对象列表
	 * @param targetType 目标对象类型
	 * 
	 * @return 目标对象列表
	 */
	public static <S, T> List<T> copyList(List<S> sources, Class<T> targetType) {
		if(sources==null){
			return null;
		}
		if(targetType==null){
			throw new IllegalArgumentException();
		}
		List<T> targets = new ArrayList<T>();
		for (S source : sources) {
			T target;
			try {
				target = targetType.getConstructor().newInstance();
			} catch (Exception e) {
				throw new IllegalArgumentException(e);
			}
			copy(source, target);
			targets.add(target);
		}
		return targets;
	}
	
	/**
	 * <h3>从列表的对象中取出某个字段的值，并组装成List</h3>
	 * 
	 * @param <S> 字段的对象类型
	 * @param <T> 源列表中的对象类型
	 * @param source 源对象列表
	 * @param fieldName 字段名称
	 * 
	 * @return 指定字段的值组装的List
	 */
	@SuppressWarnings("unchecked")
	public static <S, T> List<S> buildListByFieldName(List<T> source,
			String fieldName) {
		if (source==null){
			return null;
		}
		List<S> result = new ArrayList<S>();
		try{
			for (T obj : source) {
				Field[] fields = obj.getClass().getDeclaredFields();
				for (Field field : fields) {
					if (field.getName().equals(fieldName)) {
						if (!field.isAccessible()) {
							field.setAccessible(true);
						}
						S s=(S) field.get(obj);
						if(s!=null){
							result.add(s);
						}
					}
				}
			}
		}
		catch(Exception e){
			throw new IllegalArgumentException(e);
		}
		return result;
	}
	
	/**
	 * <h3>从列表的对象中取出某个字段的值，并组装成数组</h3>
	 * 
	 * @param <S> 字段的对象类型
	 * @param <T> 源列表中的对象类型
	 * @param source 源对象列表
	 * @param fieldName 字段名称
	 * 
	 * @return 指定字段的值组装的数组
	 */
	@SuppressWarnings("unchecked")
	public static <S, T> S[] buildArrayByFieldName(List<T> source,
			String fieldName) {
		List<S> list=buildListByFieldName(source,fieldName);
		if(list==null){
			return null;
		}
		S[] s=(S[]) Array.newInstance(list.get(0).getClass(), list.size());
		return list.toArray(s);
	}
	
	/**
	 * <h3>从列表的对象中取出某个字段的值，按指定分隔符拼装成字符串</h3>
	 * 
	 * @param <S> 字段的对象类型
	 * @param <T> 源列表中的对象类型
	 * @param source 源对象列表
	 * @param fieldName 字段名称
	 * @param separator 分隔符
	 * 
	 * @return 按指定分隔符拼装成字符串
	 */
	public static <S,T> String joinByFieldName(List<T> source,
			String fieldName,String separator) {
		if(source==null){
			return null;
		}
		if(source.isEmpty()){
			return "";
		}
		
		List<S> list=buildListByFieldName(source,fieldName);
		if(list==null || list.isEmpty()){
			return "";
		}
		StringBuffer sb=new StringBuffer("");
		for(S t:list){
			sb.append(t.toString()).append(separator);
		}
		return sb.substring(0,sb.lastIndexOf(separator));
	}
}
